<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" version="1.0" targetNamespace="http://www.geotools.org/app-schema"
  xmlns:as="http://www.geotools.org/app-schema" xmlns:ogc="http://www.opengis.net/ogc"
  xmlns:gml="http://www.opengis.net/gml">

  <import namespace="http://www.opengis.net/ogc" schemaLocation="http://schemas.opengis.net/filter/1.1.0/expr.xsd" />
  <import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/3.1.1/base/feature.xsd" />

  <element name="AppSchemaDataAccess" type="as:AppSchemaDataAccessType">
    <annotation>
      <documentation>Root element of a mappings configuration file.</documentation>
    </annotation>
  </element>

  <complexType name="AppSchemaDataAccessType">
    <annotation>
      <documentation>
        Mappings configuration element type. Defines the mappings sections needed to define the namespaces _used in the
        config file instance_, the datastores with the source feature types, the schema location for the target feature
        types and the correspondence between both as mapping elements.
      </documentation>
    </annotation>
    <sequence>
      <element name="namespaces" type="as:NamespacesPropertyType" />
      <element name="includedTypes" type="as:IncludesPropertyType" minOccurs="0" />
      <element name="sourceDataStores" type="as:SourceDataStoresPropertyType" />
      <element name="catalog" type="string" minOccurs="0">
        <annotation>
          <documentation>
            If present, the location of an OASIS catalog file that shall be used
            to resolve the community schemas. The path can be relative to the
            configuration document which validates against this schema, or well
            an absolute URI.
          </documentation>
        </annotation>
      </element>
      <element name="targetTypes" type="as:TargetTypesPropertyType" />
      <element name="typeMappings" type="as:TypeMappingsPropertyType" />
    </sequence>
  </complexType>

  <complexType name="NamespacesPropertyType">
    <annotation>
      <documentation>
        <![CDATA[
      Use this element _only_ if you're going to do polymorphic mappings. You don't need to
      specify each and every namespace used in the community schemas in this section, since they'll
      be loaded by the schema parser.
      Thus, this section is just needed at the mappings configuration parsing stage, and only if you
      need complex datastore to assign a feature property which is not of the specific type stated
      in the schema for that property, but of a derivate type.
      For example, if you have:
      <xs:complexType name="MyFeatureType">
      	<xs:complexContent>
      		<xs:extension base="gml:AbstractFeatureType">
      			<xs:sequence>
      				<xs:element name="station" type="myns:MyBaseType"/>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
      </xs:complexType>

      Now, say that myns:MyBaseType is abstract and at runtime you want that MyFeatureType instances
      being assigned an instance of myns2:MyDerivedType, which extends myns:MyBaseType.
      If you don't specify that situation in the mappings config file, complex datastore will have no
      way of inferring that, so the way of telling complex datastore to create an instance of
      myns2:MyDerivedType instead of the one declared in the schema, is by using  a 
      <targetElement>myns2:MyDerivedType</targetElement> tag in the attribute mapping (see 
      TypeMappingsPropertyType documentation below).
      So, for the mappings parser to recognize which type the instance should actually be, you
      need to declare the namespace here, as well as in the actual xsd schema.
    ]]>
      </documentation>
    </annotation>
    <sequence>
      <element name="Namespace" minOccurs="0" maxOccurs="unbounded">
        <complexType>
          <sequence>
            <element name="prefix" type="string" />
            <element name="uri" type="string" />
          </sequence>
        </complexType>
      </element>
    </sequence>
  </complexType>
  
  <complexType name="IncludesPropertyType">
	<annotation>
		<documentation>
        <![CDATA[
      This is only needed if this type has related types that do not have their own 
      Geoserver configuration, ie. not published in Geoserver. The type might be
      mapped separately so they can be reusable (feature chaining concept), e.g. 
      If feature type A contains data type B, and feature type C also contains
      data type B, we only want to have one mapping file for data type B. 
 
      The purpose of this is so that the parent type (this mapping) can find the
      related features.
      The type might not be visible on their own because it's not a feature type
      (e.g. a data type), therefore shouldn't appear in requests such as GetCapabilities,
      DescribeFeatureType etc. 
    ]]>
		</documentation>
	</annotation>
	<sequence>
		<element name="Include" minOccurs="0" maxOccurs="unbounded" />
	</sequence>
  </complexType>

  <complexType name="SourceDataStoresPropertyType">
    <annotation>
      <documentation>
        <![CDATA[
    Used to reference the origin datastores containing the source feature types, aka the
    ones that are to be mapped to the community schemas.
    A unique id has to be assigned for each source datastore, as well as all the required
    datastore factory parameters in order to allow complex datastore to find them through
    the DataStoreFactorySpi mechanism.
    ]]>
      </documentation>
    </annotation>
    <sequence>
      <element name="DataStore" minOccurs="0" maxOccurs="unbounded">
        <complexType>
          <sequence>
            <element name="id" type="string" />
            <element name="parameters">
              <complexType>
                <sequence>
                  <element name="Parameter" minOccurs="0" maxOccurs="unbounded">
                    <complexType>
                      <sequence>
                        <element name="name" type="string" />
                        <element name="value" type="string" />
                      </sequence>
                    </complexType>
                  </element>
                </sequence>
              </complexType>
            </element>
          </sequence>
          <attribute name="id" type="ID" />
        </complexType>
      </element>
    </sequence>
  </complexType>

  <complexType name="TargetTypesPropertyType">
    <annotation>
      <documentation>
        <![CDATA[
    Here you have to specify lo location of the different xsd schema files that comprises
    the community schema. You have to specify each and every involved/relevant xsd schema
    since the current schema parser does not has the ability of following includes and imports.
    Also, it would be very helpful if they're declared in the more sequential fashion possible, since
    even if the schema parser uses proxied types when it finds a type reference that haven't still
    been loaded, setting schema file locations in random order could lead to missing referencing 
    of nested types and thus causing an unrecoverable parsing time error.
    
    As for supported GML 3.1.1 types, complex datastore automatically loads the following gml schema files
    before parsing the community schemas, so if you need more gml types just add them prior to your
    own schemas:
      basicTypes.xsd
      gmlBase.xsd
      dictionary.xsd
      valueObjects.xsd
      coverage.xsd     
      measures.xsd
      geometryBasic0d1d.xsd
    
    Note that though not all the geometry schemas are loaded, you don't need to import the corresponding
    gml schemas for geometry types since (at least for SFS) they're already supported by the geotools type system.
    ]]>
      </documentation>
    </annotation>
    <sequence>
      <element name="FeatureType" minOccurs="0" maxOccurs="1">
        <complexType>
          <sequence>
            <element name="schemaUri" type="string" minOccurs="0" maxOccurs="unbounded" />
          </sequence>
        </complexType>
      </element>
    </sequence>
  </complexType>

  <complexType name="TypeMappingsPropertyType">
    <annotation>
      <documentation>
        <![CDATA[
    This is where tha magis happens. The prior sections were just support information for getting 
    to this instance. Inside this section, you have to declare one FeatureTypeMapping element
    for each feature type you want to map from an internal structure to the community schema.
    The FeatureTypeMapping element contains information as what is the internat feature type
    you want to map (given by the datastore id and feature type name), the name of the target
    element in the community schema you want to serve, and the attribute mappings between them.
    ]]>
      </documentation>
    </annotation>
    <sequence>
      <element name="FeatureTypeMapping" minOccurs="0" maxOccurs="unbounded">
        <complexType>
          <sequence>
            <element name="mappingName" type="string" minOccurs="0"/>
            <element name="sourceDataStore" type="string">
              <annotation>
                <documentation>one of the datastore ids defined in the sourceDataStores section</documentation>
              </annotation>
            </element>
            <element name="sourceType" type="string">
              <annotation>
                <documentation>
                  the feature type name inside sourceDataStore to be mapped to the community schema
                </documentation>
              </annotation>
            </element>
            <element name="targetElement" type="string">
              <annotation>
                <documentation>
                  the target element type. Note that this has to be an element type and not a feature type. Thus, the
                  referenced element has to be of the desired feature type (for example, xmml:Borehole instead of
                  xmml:BoreHoleType)
                </documentation>
              </annotation>
            </element>
            <element name="itemXpath" type="string" minOccurs="0">
              <annotation>
                <documentation>
                  The xpath that identifies separate features in the xml returned from an xml datastore.
                </documentation>
              </annotation>
            </element>
            <element name="isXmlDataStore" type="boolean" default="false" minOccurs="0">
              <annotation>
                <documentation>
                  <![CDATA[ 
                  Flag to indicate that we want to connect to an xml data source]]>
                </documentation>
              </annotation>
            </element>
            <element name="isDenormalised" type="boolean" default="true" minOccurs="0">
              <annotation>
                <documentation>
                  <![CDATA[
                  Flag to indicate if the data is denormalised or not. The value will determine how the SQL query to handle maxFeatures and startIndex will be built. ]]>
                </documentation>
              </annotation>
            </element>
            <element name="attributeMappings" minOccurs="0">
              <annotation>
                <documentation>
                  <![CDATA[
            Now it is time to map every target attribute with an expression from the source feature type. Generally,
            you only have to specify attribute mappings for those target attributes that are "leaf", aka, simlpe properties.
            The exception is when you have a multivalued complex attribute, in which case you have to create
            an AttributeMapping for the attribute to tell complex datastore to create as many instances of that
            complex attribute as source features fits the current "group" of a joined result.
            See the documentation for SingleMappingType and AttributeMappingType to lear what the structure of
            an attribute mapping is.
            Examples:
            
            --------------
            The simplest possible mapping, maps the source attribute BGS_ID to the name attribute of Borehole
            <AttributeMapping>
              <targetAttribute>Borehole/name</targetAttribute>
              <sourceExpression><OCQL>BGS_ID</OCQL></sourceExpression>
            </AttributeMapping>

            --------------
            Uses a function expression to map the result to the second instance of the name attribute.
            Also adds a "client property" named "codeSpace" with a fixed value. This leads to
            an xml attribute at GML encoding time.
            
            <AttributeMapping>
              <targetAttribute>Borehole/name[2]</targetAttribute>
              <sourceExpression><OCQL>strConcat(BGS_ID, 'name-#')</OCQL></sourceExpression>
              <ClientProperty>
                <name>codeSpace</name><value>"http://ns.bgs.ac.uk/bgs.ubi.pk"</value>
              </ClientProperty>
            </AttributeMapping>
            
            --------------
            Tells complex datastore to create an instance of range for each "row" of the same "group" of a
            joined result for a joined source feature type. No need to set sourceExpression since "range"
            attribute is complex and thus will have to set the mappings for its childs anyways.
            NOTE in this case we ommited "Borehole/" on the targetAttribute content. It is intentional, as
            and it should work both ways, as the filter encoding spec says that the root element name is 
            optional.
            
            <AttributeMapping>
              <targetAttribute>log/IntervalLog/range</targetAttribute>
              <isMultiple>true</isMultiple>
            </AttributeMapping>

            ]]>
                </documentation>
              </annotation>
              <complexType>
                <sequence>
                  <element name="AttributeMapping" minOccurs="0" maxOccurs="unbounded" type="as:AttributeMappingType" />
                </sequence>
              </complexType>
            </element>
          </sequence>
        </complexType>
      </element>
    </sequence>
  </complexType>

  <complexType name="AttributeExpressionMappingType">
    <annotation>
      <documentation>
        <![CDATA[
      Allows to specify the OGC's Common Query Language expression to be used
      as the source for a community schema element's content.
    ]]>
      </documentation>
    </annotation>
    <sequence>
      <choice minOccurs="0">
        <sequence>            
          <element name="OCQL" type="string" />          
          <element name="index" type="string" minOccurs="0" maxOccurs="1">
            <annotation>
              <documentation>
                <![CDATA[ The index of database row if denormalised. Example of usage is timeseries endPosition that reflects the last timePosition where the timePosition value is dynamic. ]]>
              </documentation>
            </annotation>
          </element>
        </sequence>
        <element name="Expression">
          <complexType>
            <sequence>
              <element ref="ogc:expression" />
            </sequence>
          </complexType>
        </element>
        <element name="inputAttribute" type="string">
          <annotation>
            <documentation>
              <![CDATA[ XPath expression addressing the input schema element this attribute mapping refers to ]]>
            </documentation>
          </annotation>
        </element>
      </choice>
      <element name="linkElement" type="string" minOccurs="0" maxOccurs="1">
        <annotation>
          <documentation>
            <![CDATA[ XPath expression addressing the target schema element this attribute mapping is nesting ]]>
          </documentation>
        </annotation>
      </element>
      <element name="linkField" type="string" minOccurs="0" maxOccurs="1">
        <annotation>
          <documentation>
            <![CDATA[ XPath expression addressing the target attribute this attribute mapping links to ]]>
          </documentation>
        </annotation>
      </element>
    </sequence>
  </complexType>

  <complexType name="AttributeMappingType">
    <annotation>
      <documentation>
        <![CDATA[
      Allows to specify the OGC's Common Query Language expression to be used
      as the source for a community schema element's content, as long as wether
      it is a multivalued property, which target schema element should be created
      instead of the default declared on the target schema, and any number
      of client properties (aka, xml element attributes)
    ]]>
      </documentation>
    </annotation>
    <sequence>
      <element name="label" type="string" minOccurs="0">
        <annotation>
          <documentation>
            <![CDATA[ Name by which other attributes can uniquely refer to this attribute. (Used in xml datastores.) ]]>
          </documentation>
        </annotation>
      </element>
      <element name="parentLabel" type="string" minOccurs="0" >
        <annotation>
          <documentation>
            <![CDATA[ A reference to another attribute which has a label tag. The parentLabel has the name contained in the other attributes label tag. (Used in xml datastores.) ]]>
          </documentation>
        </annotation>
      </element>      
      <element name="targetAttribute" type="string">
        <annotation>
          <documentation>
            <![CDATA[ XPath expression addressing the target schema element this attribute mapping refers to ]]>
          </documentation>
        </annotation>
      </element>
      <element name="targetQueryString" type="string" minOccurs="0">
          <annotation>
          <documentation>
            <![CDATA[ Used to translate a reference to an attribute in an incoming filter to the element used in an xml datastore.]]>
          </documentation>
        </annotation>
      </element>      
      <element name="idExpression" minOccurs="0" type="as:AttributeExpressionMappingType">
        <annotation>
          <documentation>
            <![CDATA[ CQL expression whose evaluated value over the Features of the 
            surrogate datastore is to be usedas the ID value for the target schema 
            attribute this AttributeMapping refers to ]]>
          </documentation>
        </annotation>
      </element>
      <element name="sourceExpression" minOccurs="0" type="as:AttributeExpressionMappingType">
        <annotation>
          <documentation>
            <![CDATA[ CQL Expression whose evaluated value over the Feature(s) of the 
            surrogate datastore is to be used as the value for the target schema attribute 
            this AttributeMapping refers to ]]>
          </documentation>
        </annotation>
      </element>
      <element name="instancePath" type="string" minOccurs="0">
        <annotation>
          <documentation>
            <![CDATA[ When counting how many complex types to create in a label/parentlabel tree, this is the path to use to count instances in the input data. ]]>
          </documentation>
        </annotation>
      </element>
      <element name="targetAttributeNode" type="string" minOccurs="0">
        <annotation>
          <documentation>
            <![CDATA[ name of a top level element declaration in the target schema which has to be instantiated
            when creating this attribute instead of the one declared in the target schema. This is to support
            the cases where the schema states a given element, which might be abstract, and we want an specific
            kind of element to be used, which should be in the schema's declared element substitution group
            according to the GML rules, though AppSchemaDataAccess will not check for it. ]]>
          </documentation>
        </annotation>
      </element>
      <element name="isMultiple" type="boolean" default="false" minOccurs="0">
        <annotation>
          <documentation>
            <![CDATA[ Flag to indicate the target element addressed by this mapping has to be treated as
            a multivalued property. AppSchemaDataAccess will treat all the attribute mappings having this flag
            set to true as multivalued attributes and will create as many instances of it as Features of
            the surrogate datastore lie inside the FeatureTypeMapping ]]>
          </documentation>
        </annotation>
      </element>
      <element name="encodeIfEmpty" type="boolean" default="false" minOccurs="0">
        <annotation>
          <documentation>
            <![CDATA[ Flag to determine whether to skip a attribute mapping if it is empty default to false]]>
          </documentation>
        </annotation>
      </element>
      <element name="isList" type="boolean" default="false" minOccurs="0">
        <annotation>
          <documentation>
            <![CDATA[ Flag to indicate the target element addressed by this mapping has to be treated as
            a container of a list of values. This is similar to isMultiple except the values are concatenated
            as one big value instead of multiple elements with each value.]]>
          </documentation>
        </annotation>
      </element>
      <element name="ClientProperty" minOccurs="0" maxOccurs="unbounded">
        <complexType>
          <sequence>
            <element name="name" type="string">
              <annotation>
                <documentation>name of the client property/xml element attribute</documentation>
              </annotation>
            </element>
            <element name="value" type="string">
              <annotation>
                <documentation>OGC CQL expression for the attribute value</documentation>
              </annotation>
            </element>
          </sequence>
        </complexType>
      </element>
    </sequence>
  </complexType>
</schema>
